/**
 * Aibton.com Inc.
 * Copyright (c) 2016-2017 All Rights Reserved.
 */
package com.aibton.framework.util;

import java.nio.charset.Charset;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import com.aibton.framework.config.AibtonConstantKey;
import com.aibton.framework.exception.RequestException;

/**
 * 操作HTTP工具类
 * @author huzhihui
 * @version $: v 0.1 2017 2017/7/19 16:04 huzhihui Exp $$
 */
@Component
public class RestTemplateUtils {

    @Bean
    public RestTemplate restTemplate() {
        StringHttpMessageConverter m = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        RestTemplate restTemplate = new RestTemplateBuilder().additionalMessageConverters(m)
            .build();
        return restTemplate;
    }

    private static RestTemplate restTemplate = (RestTemplate) SpringContextUtils
        .getBean("restTemplate");

    private static final Logger LOGGER       = LoggerFactory.getLogger(RestTemplateUtils.class);

    /**
     * GET方法调用其他服务器
     * @param url   httpUrl  如http://www.aibton.com
     * @param responseType  返回值类型
     * @param uriVariables  url对应的值{aa}     aa
     * @param <T>   泛型
     * @return  泛型对象
     */
    public static <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) {
        try {
            return restTemplate.getForObject(url, responseType, uriVariables);
        } catch (Exception ex) {
            LoggerUtils.error(LOGGER, ExceptionUtils.getExceptionString(ex));
            throw new RequestException(AibtonConstantKey.HTTP_ERROR);
        }
    }

    /**
     * GET方法调用其他服务器
     * @param url   httpUrl
     * @param responseType  返回值类型
     * @param map   GET请求的参数以键值对的方式传过来，该方法自动拼接URL
     * @param <T>    泛型
     * @return  泛型对象
     */
    public static <T> T getForObject(String url, Class<T> responseType, Map<String, String> map) {
        try {
            StringBuilder urlAfter = new StringBuilder("?");
            for (Map.Entry<String, String> entry : map.entrySet()) {
                if (urlAfter.toString().equals("?")) {
                    urlAfter.append(entry.getKey() + "=" + entry.getValue());
                } else {
                    urlAfter.append("&" + entry.getKey() + "=" + entry.getValue());
                }

            }
            url = url + urlAfter.toString();
            String reslut = restTemplate.getForObject(url, String.class);
            return JackSonUtils.jsonStrToObject(reslut, responseType);
        } catch (Exception ex) {
            LoggerUtils.error(LOGGER, ExceptionUtils.getExceptionString(ex));
            throw new RequestException(AibtonConstantKey.HTTP_ERROR);
        }
    }

    /**
     * GET方法调用其他服务器
     * @param url   httpUrl
     * @param responseType  返回值类型
     * @param <T>   泛型
     * @return  泛型对象
     */
    public static <T> T getForObject(String url, Class<T> responseType) {
        try {
            return restTemplate.getForObject(url, responseType);
        } catch (Exception ex) {
            LoggerUtils.error(LOGGER, ExceptionUtils.getExceptionString(ex));
            throw new RequestException(AibtonConstantKey.HTTP_ERROR);
        }
    }

    /**
     * POST方法调用其他服务器    对方接收参数为@RequestBody对象类型
     * @param url   httpUrl
     * @param request   json字符串
     * @param responseType  返回值类型
     * @param uriVariables  url对应的值{aa}     aa
     * @param <T>   泛型
     * @return  泛型对象
     */
    public static <T> T postForObject(String url, String request, Class<T> responseType,
                                      Object... uriVariables) {
        try {
            HttpHeaders headers = new HttpHeaders();
            MediaType type = MediaType
                .parseMediaType(MediaType.APPLICATION_JSON_UTF8_VALUE.toString());
            headers.setContentType(type);
            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
            HttpEntity<String> formEntity = new HttpEntity<String>(request, headers);
            return restTemplate.postForObject(url, formEntity, responseType, uriVariables);
        } catch (Exception ex) {
            LoggerUtils.error(LOGGER, ExceptionUtils.getExceptionString(ex));
            throw new RequestException(AibtonConstantKey.HTTP_ERROR);
        }
    }

    /**
     * POST方法调用其他服务器
     * @param url   httpUrl
     * @param request   header一类的信息
     * @param responseType  返回值类型
     * @param uriVariables  POST请求的参数以键值对的方式传过来，该方法自动拼接URL
     * @param <T>   泛型
     * @return  泛型对象
     */
    public static <T> T postForObject(String url, Object request, Class<T> responseType,
                                      Map<String, ?> uriVariables) {
        try {
            return restTemplate.postForObject(url, request, responseType, uriVariables);
        } catch (Exception ex) {
            LoggerUtils.error(LOGGER, ExceptionUtils.getExceptionString(ex));
            throw new RequestException(AibtonConstantKey.HTTP_ERROR);
        }
    }

    /**
     * POST方法调用其他服务器
     * @param url   httpUrl
     * @param request   请求的键值对 如：(name,age)    map.put(name,) map.put(age,)
     * @param responseType  返回值类型
     * @param <T>   泛型
     * @return  泛型对象
     */
    public static <T> T postForObject(String url, Map<String, String> request,
                                      Class<T> responseType) {
        try {
            HttpHeaders headers = new HttpHeaders();
            MediaType type = MediaType
                .parseMediaType(MediaType.APPLICATION_FORM_URLENCODED_VALUE.toString());
            headers.setContentType(type);

            MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
            request.keySet().stream().forEach(key -> requestEntity.add(key, request.get(key)));
            HttpEntity<String> formEntity = new HttpEntity<String>(requestEntity);
            return restTemplate.postForObject(url, formEntity, responseType);
        } catch (Exception ex) {
            LoggerUtils.error(LOGGER, ExceptionUtils.getExceptionString(ex));
            throw new RequestException(AibtonConstantKey.HTTP_ERROR);
        }
    }
}
